﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using DynamicLoader;
using System.Globalization;
using System.Threading;
using System.ServiceModel;
using System.Net.NetworkInformation;

namespace SSCCMembership
{
    public partial class App : Application
    {
        public static Grid LayoutRoot { get; set; }

        public App()
        {
            this.Startup += this.Application_Startup;
            this.Exit += this.Application_Exit;
            this.UnhandledException += this.Application_UnhandledException;

            Thread.CurrentThread.CurrentCulture = new CultureInfo("en-GB");
            Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-GB");


            InitializeComponent();

        }

        private void Application_Startup(object sender, StartupEventArgs e)
        {
            this.RootVisual = new MainPage();
            //DynamicLoader.DataStructures.XAPName.EstimatedFileSizes = new Dictionary<DynamicLoader.DataStructures.XAPName, long>()
            //{
            //    {"FloatableWindow.xap", 16789},
            //    {"System.Windows.Controls.xap", 90017},
            //    {"System.Windows.Data.xap", 215598},
            //    {"BindableDataGrid.xap",5422}
            //};
            //Load what we know we'll need
            Cache.Enque("SSCCMembershipContent.xap", 0);
            Cache.Enque("U_UserHome.xap", 0);
            //Load XAPs that anyone can access
            Cache.Enque("P_PersonalDetails.xap", 0);
            //Load dependancies for lots of things
            Cache.Enque("System.Windows.Controls.xap", 4);
            Cache.Enque("System.Windows.Controls.Input.xap", 4);
            Cache.Enque("RefCodes.xap", 0);
            Cache.Enque("FloatableWindow.xap", 4);
            Cache.Enque("System.Windows.Data", 4);
            Cache.Enque("BindableDataGrid.xap", 4);
            //Load all other XAPs

            Cache.Enque("A_DirectDBAccess.xap", 0);
            Cache.Enque("A_ManageUsers.xap", 0);
            Cache.Enque("A_ReferenceCodes.xap", 0);

            if (IsRunningOutOfBrowser)
            {
                CheckAndDownloadUpdateCompleted += new CheckAndDownloadUpdateCompletedEventHandler(App_CheckAndDownloadUpdateCompleted);
                CheckAndDownloadUpdateAsync();
            }
        }

        void App_CheckAndDownloadUpdateCompleted(object sender, CheckAndDownloadUpdateCompletedEventArgs e)
        {
            if (e.UpdateAvailable)
            {

            }
        }

        private void Application_Exit(object sender, EventArgs e)
        {

        }

        private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
        {
            // If the app is running outside of the debugger then report the exception using
            // the browser's exception mechanism. On IE this will display it a yellow alert 
            // icon in the status bar and Firefox will display a script error.
            if (!System.Diagnostics.Debugger.IsAttached)
            {

                // NOTE: This will allow the application to continue running after an exception has been thrown
                // but not handled. 
                // For production applications this error handling should be replaced with something that will 
                // report the error to the website and stop the application.
                e.Handled = true;
                //if (KnownExes.Any(KnownEx.IsMatch(e.ExceptionObject)))
                //{
                var ex = KnownExes.First(KnownEx.IsMatch(e.ExceptionObject)).Action(e.ExceptionObject.GetBaseException());
                if (NetworkInterface.GetIsNetworkAvailable() && ex.IsReportable)
                {
                    Services.LoggingService.LoggingServiceClient LSC = new Services.LoggingService.LoggingServiceClient();
                    LSC.LogCompleted += (s, ea) =>
                    {
                        if (ea.Cancelled || ea.Error != null)
                        {
                            BusyIndicator.Show(ex.UserMessage,
                                HasProgress: false, SecondsTimeout: 60, EnableUserClose: true);
                        }
                        else
                        {
                            BusyIndicator.Show(ex.UserUploadedMessage,
                                HasProgress: false, SecondsTimeout: 60, EnableUserClose: true);
                        }

                    };
                    BusyIndicator.Show(ex.UserUploadingMessage,
                            HasProgress: true, EnableUserClose: false);
                    LSC.LogAsync(ex.Report);
                }
                else
                {
                    BusyIndicator.Show(ex.UserMessage,
                        HasProgress: false, SecondsTimeout: 60, EnableUserClose: true);
                }
                //}
                //else
                //{
                //    var ex = e.ExceptionObject.GetBaseException();
                //    if (ex is System.ServiceModel.CommunicationException)
                //    {
                //        if (!System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
                //        {
                //            BusyIndicator.Show("Error: You are not currently connected to a network.", false, 60, true);
                //        }
                //        else
                //        {
                //            BusyIndicator.Show("Error: There was a communication error, are you connected to the internet?", false, 60, true);
                //        }
                //        return;
                //    }
                //    BusyIndicator.Show("Error: " + ex.Message, false, 60, true);
                //    Deployment.Current.Dispatcher.BeginInvoke(delegate { ReportErrorToDOM(e); });
                //}

            }
        }
        private void ReportErrorToDOM(ApplicationUnhandledExceptionEventArgs e)
        {
            try
            {
                string errorMsg = e.ExceptionObject.Message + e.ExceptionObject.StackTrace;
                errorMsg = errorMsg.Replace('"', '\'').Replace("\r\n", @"\n");

                System.Windows.Browser.HtmlPage.Window.Eval("throw new Error(\"Unhandled Error in Silverlight Application " + errorMsg + "\");");
            }
            catch (Exception)
            {
            }
        }

        KnownEx[] KnownExes = new KnownEx[] 
        { 
            new KnownEx(typeof(CommunicationException), (ex)=>
                new KnownExResult((NetworkInterface.GetIsNetworkAvailable())?"There was an error processing data on the server, please ensure you have entered sensible values into any data entry boxes or try again later":"You are no longer connected to the internet, SSCC Membership can only work while connected.")),
            new KnownEx(typeof(Exception), (ex)=>
                new KnownExResult("There was an unhandled error and you don't appear to be connected to the internet. Please reconnect and try again.", "There was an unhandled error, this is being reported automatically.", "The error was reported.", ex.ToString()))
        };
        class KnownEx
        {
            public KnownEx(Type Exception, Func<Exception, KnownExResult> Action)
            {
                this.Exception = Exception;
                this.Action = Action;
            }
            public Type Exception;
            public Func<Exception, KnownExResult> Action;
            public static Func<KnownEx, bool> IsMatch(Exception ex)
            {
                return new Func<KnownEx, bool>((K) => K.Exception.IsAssignableFrom(ex.GetBaseException().GetType()));
            }
        }
        class KnownExResult
        {
            public KnownExResult(string UserMessage)
            {
                this.UserMessage = UserMessage;
                this.IsReportable = false;
            }
            public KnownExResult(string UserMessage, string UserUploadingMessage, string UserUploadedMessage, string Report)
            {
                this.UserMessage = UserMessage;
                this.UserUploadedMessage = UserUploadedMessage;
                this.UserUploadingMessage = UserUploadingMessage;
                this.IsReportable = true;
                this.Report = Report;
            }
            public string Report { get; set; }
            public bool IsReportable { get; set; }
            public string UserUploadingMessage { get; set; }
            public string UserUploadedMessage { get; set; }
            public string UserMessage { get; set; }
        }
    }

}